package com.sangeng.service.serviceimpl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sangeng.constants.SystemConstants;
import com.sangeng.domain.ResponseResult;
import com.sangeng.domain.entity.Article;
import com.sangeng.domain.entity.Category;
import com.sangeng.domain.vo.ArticleDetailVo;
import com.sangeng.domain.vo.ArticleListVo;
import com.sangeng.domain.vo.HotArticleVo;
import com.sangeng.domain.vo.PageVo;
import com.sangeng.mapper.ArticleMapper;
import com.sangeng.mapper.CategoryMapper;
import com.sangeng.service.ArticleService;

import com.sangeng.utils.BeanCopyUtils;
import com.sangeng.utils.RedisCache;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;


import static com.sangeng.constants.SystemConstants.HOTARTICLE_PAGE;
import static com.sangeng.constants.SystemConstants.HOTARTICLE_PAGE_SIZE;

@Service
@RequiredArgsConstructor
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {
    //利用该Service传入分类id查询分类数据
    private final CategoryMapper categoryMapper;

    @Override
    public ResponseResult<List<HotArticleVo>> hotArticleList() {
        //需求：查询浏览量最高的前十篇文章信息 不能展示草稿 不能展示已经逻辑删除的 要按照浏览量排序
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();//封装查询条件
        //条件1：必须是正式发布的文章
        //比较Status字段
        queryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL);
        //条件2：按照浏览量排序 （已删除文章已经在yml里的mp配置了，不用再配置）
        //获取浏览量
        queryWrapper.orderByDesc(Article::getViewCount);
        //条件3：最多10条文章信息
        // 1页 10条
        Page<Article> page = new Page<>(HOTARTICLE_PAGE, HOTARTICLE_PAGE_SIZE);
        page(page, queryWrapper);

        List<Article> articles = page.getRecords();
        //实际上article有太多前端不需要也不应该看见的字段 所以应该拷贝到hotarticleVo
        //此外，一般不要在数据库对应的映射类作符合接口的修改，而是用vo类
        //bean拷贝
        List<HotArticleVo> hotArticleVos = new ArrayList<>();
        for (Article article : articles) {
            HotArticleVo vo = new HotArticleVo();
            BeanUtils.copyProperties(article, vo);
            hotArticleVos.add(vo);
        }

        //okResult生成ResponseResult对象
        return ResponseResult.okResult(hotArticleVos);
    }

    @Override
    public ResponseResult<PageVo> articleList(Integer pageNum, Integer pageSize, Long categoryId) {
        //首页 查询所有文章
        //分类页面 查询对应分类下的文章
        //查询条件
        LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();//封装查询条件
        //如果 有categoryId 就要 查询时要和传入的相同
        //mybatis plus的动态sql写法，如果第一个condition参数为true，则进行后面两个值的判断
        lambdaQueryWrapper.eq(Objects.nonNull(categoryId) && categoryId > 0, Article::getCategoryId, categoryId);
        //状态是正式发布的
        lambdaQueryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL);
        //对isTop字段进行降序查询，因为isTop=1是置顶的，0则相反，降序排列可以把置顶文章放前面.
        lambdaQueryWrapper.orderByDesc(Article::getIsTop);
        //分页查询
        Page<Article> page = new Page<>(pageNum, pageSize);
        page(page, lambdaQueryWrapper);

        //查询categoryName分类名称
        //但是我们的实体类里面只有分类的id，是没有分类名称的，所以我们需要在Article里面增加一个分类名称字段
        //注意，该字段在数据表中是不存在的，所以要加上表名不存在的注释
        List<Article> articles = page.getRecords();
        //articleId查询articleName进行设置
//        for (Article article : articles) {
//            Category category = categoryService.getById(article.getCategoryId());
//            article.setCategoryName(category.getName());
//        }

//        stream流获取分类名字写法
        articles.stream()
                .map((Function<Article, Object>) article -> {
                    //步骤: 获取分类id 查询分类信息 获取分类名称
                    Category category = categoryMapper.selectById(article.getCategoryId());
                    String name = category.getName();
                    article.setCategoryName(name);
                    return article;
                });

        //封装查询结果vo
        List<ArticleListVo> articleListVos = BeanCopyUtils.copyBeanList(page.getRecords(), ArticleListVo.class);

        //再封装成分页的vo 具体原因看分页vo代码
        PageVo pageVo = new PageVo(articleListVos, page.getTotal());
        return ResponseResult.okResult(pageVo);
    }

    @Override
    public ResponseResult<ArticleDetailVo> getArticleDetail(Long id) {
        //根据id查询文章
        Article article = getById(id);
        //从redis中获取viewCount
        Integer viewCount = redisCache.getCacheMapValue("article:viewCount", id.toString());
        if (viewCount != null)//防止redis挂了的时候页面不显示数据
            article.setViewCount(viewCount.longValue());
        //转换为vo
        ArticleDetailVo articleVo = BeanCopyUtils.copyBean(article, ArticleDetailVo.class);
        //根据分类id查询分类名称（左上角显示的分类名称）
        Long categoryId = articleVo.getCategoryId();
        Category category = categoryMapper.selectById(categoryId);//getById(categoryId);
        if (category != null) {
            articleVo.setCategoryName(category.getName());
        }
        //封装响应返回
        return ResponseResult.okResult(articleVo);
    }

    private final RedisCache redisCache;

    @Override
    public ResponseResult<String> updateViewCount(Long id) {
        //更新redis数据库中对应id的文章浏览量
        redisCache.incrementCacheMapValue("article:viewCount", id.toString(), 1);
        return ResponseResult.okResult();
    }
}